package com.hm.gateway.filter;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import com.hm.common.Constant;
import com.hm.common.utils.DateUtils;
import com.hm.common.utils.StringUtils;
import com.hm.gateway.service.LogService;

import reactor.core.publisher.Mono;

/**
 * 
 * @author hwg
 *
 *         2020年12月18日
 */
@Component
public class LogFilter implements GlobalFilter, Ordered {
	Logger logger = LoggerFactory.getLogger(LogFilter.class);

	static Set<String> staticFiles = new HashSet<String>() {
		{
			add(".css");
			add(".js");
			add(".html");
			add(".htm");
			add(".txt");
			add(".text");
			add(".json");

			//字体文件
			add(".eot");
			add(".otf");
			add(".fon");
			add(".font");
			add(".ttf");
			add(".ttc");
			add(".woff");
			add(".woff2");

			//图片
			add(".bmp");
			add(".jpg");
			add(".png");
			add(".tif");
			add(".gif");
			add(".pcx");
			add(".tga");
			add(".exif");
			add(".fpx");
			add(".svg");
			add(".psd");
			add(".cdr");
			add(".pcd");
			add(".dxf");
			add(".ufo");
			add(".eps");
			add(".ai");
			add(".raw");
			add(".WMF");
			add(".webp");
			add(".avif");
		}
	};

	@Autowired
	private LogService logService;

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		String path = exchange.getRequest().getURI().getPath();

		if (isStaticFile(path)) {//静态文件不记录日志
			return chain.filter(exchange);
		}

		String reqId = exchange.getRequest().getId();
		String method = exchange.getRequest().getMethod().name();

		Map<String, Object> logMap = new HashMap<String, Object>();
		logMap.put("reqId", reqId);
		logMap.put("reqUrl", path);
		logMap.put("reqTime", DateUtils.now().getTime());
		logMap.put("clientIp", getRemoteHostIp(exchange.getRequest()));
		logMap.put("clientName", getUserAgent(exchange.getRequest()));
		logMap.put("method", method);

		return chain.filter(exchange).then(Mono.fromRunnable(() -> {
			String token = exchange.getRequest().getHeaders().getFirst(Constant.token);
			if (StringUtils.isEmpty(token)) {
				token = exchange.getResponse().getHeaders().getFirst(Constant.token);
			}

			String userId = exchange.getRequest().getHeaders().getFirst(Constant.USER_ID);
			if (StringUtils.isEmpty(userId)) {
				userId = exchange.getResponse().getHeaders().getFirst(Constant.USER_ID);
			}

			if (StringUtils.isEmpty(token) || StringUtils.isEmpty(userId)) {
				return;
			}

			String functionModule = exchange.getResponse().getHeaders().getFirst(Constant.REQUEST_FUNCTION_MODULE);
			String functionCode = exchange.getResponse().getHeaders().getFirst(Constant.REQUEST_FUNCTION_CODE);
			String functionDesc = exchange.getResponse().getHeaders().getFirst(Constant.REQUEST_FUNCTION_DESC);

			try {
				functionDesc = StringUtils.decodeUrl(functionDesc);
			} catch (UnsupportedEncodingException e) {
				logger.error("解码错误", e);
			}

			HttpStatus statusCode = exchange.getResponse().getStatusCode();

			logMap.put("token", token);
			logMap.put("userId", userId);
			logMap.put("functionModule", functionModule);
			logMap.put("functionCode", functionCode);
			logMap.put("functionDesc", functionDesc);
			logMap.put("statusCode", statusCode.value());
			logMap.put("respTime", DateUtils.now().getTime());
			logMap.put("respDuration", (long) logMap.get("respTime") - (long) logMap.get("reqTime"));
			logService.addLog(logMap);
		}));
	}

	public boolean isStaticFile(String path) {
		if (!path.contains(".")) {
			return false;
		}
		String postfix = path.substring(path.lastIndexOf("."), path.length());
		if (StringUtils.isEmpty(postfix)) {
			return false;
		}
		return staticFiles.contains(postfix.toLowerCase());
	}

	public static String getRemoteHostIp(ServerHttpRequest request) {
		String ip = request.getHeaders().getFirst("x-forwarded-for");
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeaders().getFirst("Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeaders().getFirst("WL-Proxy-Client-IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeaders().getFirst("HTTP_CLIENT_IP");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeaders().getFirst("HTTP_X_FORWARDED_FOR");
		}
		if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
			try {
				ip = request.getRemoteAddress().getAddress().getHostAddress();
			} catch (Exception e) {
			}
		}
		return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
	}

	public static String getUserAgent(ServerHttpRequest request) {
		return request.getHeaders().getFirst("user-agent");
	}

	@Override
	public int getOrder() {
		return -998;
	}

}
